package test.link;

import java.util.Iterator;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentSkipListMap;

public class DebugRegister {
	
	private int lastOrder = 0;

	public Queue<byte[]> sendQueue;
	
	private SortedMap<Integer, DebugRegister.CodePoint> cpHis = new ConcurrentSkipListMap<Integer, DebugRegister.CodePoint>();
	private SortedMap<Integer, OutByte> cOutHis = new ConcurrentSkipListMap<Integer, OutByte>();
	private SortedMap<Integer, InByte> cInHis = new ConcurrentSkipListMap<Integer, InByte>();
	
	private CodePoint curCp;
	public void setCp(CodePoint cp){
		if(cp != CodePoint.WAITING)
			cpHis.put(lastOrder++, cp);
		curCp = cp;
	}
	public CodePoint getCp(){
		return curCp;
	}
	
	public byte[] packRec; //the current packet that is being received (only bytes received so far are in this array)
	
	public byte[] packSend; //the current packet that is being send (only bytes still left to send are in this array)
	
	private byte curCableOut;
	public void setCableOut(byte i){
		curCableOut = i;
		cOutHis.put(lastOrder++, new OutByte(i));
	}
	public byte getCableOut(){
		return curCableOut;
	}
	
	private byte curCableIn;
	public void setCableIn(byte i){
		curCableIn = i;
		cInHis.put(lastOrder++, new InByte(i));
	}
	public byte getCableIn(){
		return curCableIn;
	}
	
	public void printHistory(boolean cp, boolean in, boolean out){
		e("CodePoint\tIn\tOut\t");
		
		Integer ci = Integer.MAX_VALUE;
		Integer ii = Integer.MAX_VALUE;
		Integer oi = Integer.MAX_VALUE;
		
		
		do{
			try{
				ci = cpHis.firstKey();
			} catch(NoSuchElementException e) { ci = Integer.MAX_VALUE; }
			try{
				ii = cInHis.firstKey();
			} catch(NoSuchElementException e) { ii = Integer.MAX_VALUE; }
			try{
				oi = cOutHis.firstKey();
			} catch(NoSuchElementException e) { oi = Integer.MAX_VALUE; }
			if(!cp)
				ci = Integer.MAX_VALUE;
			if(!in)
				ii = Integer.MAX_VALUE;
			if(!out)
				oi = Integer.MAX_VALUE;
			if(ci < ii && ci < oi){ //ci is the smallest
				e(cpHis.get(ci).toString());
				cpHis.remove(ci);
			} else if (ii < ci && ii < oi){
				e("\t\t"+cInHis.get(ii).toString());
				cInHis.remove(ii);
			} else if (oi < ci && oi < ii){
				e("\t\t\t\t"+cOutHis.get(oi).toString());
				cOutHis.remove(oi);
			}
		}while(ci != Integer.MAX_VALUE || ii != Integer.MAX_VALUE || oi != Integer.MAX_VALUE);
	}
	
	
	private DebugRegister(){}
	
	private static DebugRegister inst = null;
	public static DebugRegister getInstance(){
		if(inst == null)
			inst = new DebugRegister();
		return inst;
	}
	
	
	public enum CodePoint{
		WAITING, //run-loop
		BEFORE_REC, AFTER_REC, //run-RECEIVING
		BEFORE_SEND, AFTER_SEND, //run-SENDING
		REC_SS1, REC_SS0, REC_LOOP, REC_LOOP_GT_MAX, REC_NOT_CORRECTABLE, REC_END_TRANSMISSION, REC_TIMEOUT, //rec()
		RRB_B1A, RRB_B1B, RRB_B2A, RRB_B2B, //readRealByte()
		RN_S0_WAIT, RN_S1_D, RN_S0_D, RN_COULD_BE_STOP, //readNibble()
		SF_SS1, SF_SS0, SF_D1, SF_D0, SF_ST1, SF_ST0, //SendFrame()
		SAW_1, SAW_0; //SendAndWait()		
	}
	
	
	private static void e(String s){
		System.out.println(s);
	}
	
	private class InByte{
		public byte val;		
		public InByte(byte b) { val = b; }
		@Override
		public String toString(){
			return bin(val);
		}
		
		private String bin(byte i){
			String x = Integer.toBinaryString(i);
			while(x.length() < 8)
				x = "0" + x;
			return "0bxxx"+(x.substring(x.length()-5, x.length()));
		}
	}
	
	private class OutByte{
		public byte val;
		public OutByte(byte b) { val = b; }
		@Override
		public String toString(){
			return bin(val);
		}
		
		private String bin(byte i){
			String x = Integer.toBinaryString(i);
			while(x.length() < 8)
				x = "0" + x;
			return "0bxxx"+(x.substring(x.length()-5, x.length()));
		}
	}
}
